#include "adc.h"
#include "rcc.h"


/** @defgroup ADC_Private_Functions
  * @{
  */

/**
  * @brief  Deinitializes the ADCx peripheral registers to their default reset values.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @retval None
  */
void ADC_DeInit(ADC_TypeDef* ADCx)
{
	
	if(ADCx == ADC)
	{
		RCC_APB1PeriphResetCmd(RCC_APB1Periph_ADC, ENABLE);
		RCC_APB1PeriphResetCmd(RCC_APB1Periph_ADC, DISABLE);
	}

}

/**
  * @brief  Initializes the ADCx peripheral according to the specified parameters
  *         in the ADC_InitStruct.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @param  ADC_InitStruct: pointer to an ADC_InitTypeDef structure that contains
  *         the configuration information for the specified ADC peripheral.
  * @retval None
  */
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
{
	
	uint16_t adccfg_reg = 0;
  uint16_t adcctrl_reg = 0;
	uint16_t adcseq_reg = 0;
	
	
	adccfg_reg = ADCx->ADCCFG;
	adcctrl_reg = ADCx->ADCCTRL;
	adcseq_reg = ADCx->ADCSEQ;
	
	adccfg_reg &= ~ADC_CFG_Vref_Mask;
	adccfg_reg &= ~ADC_CFG_SampleTim_Mask;
	adccfg_reg |= (ADC_InitStruct->ADC_SampleTime<<2)&ADC_CFG_SampleTim_Mask;
	
	adccfg_reg &= ~ADC_CFG_CHx_Mask;
	adccfg_reg |= (ADC_InitStruct->ADC_Channel<<8)&ADC_CFG_CHx_Mask;
	//ADCCTRL
	adcctrl_reg &= ~ADC_CTRL_ConvTrig_Mask;
	adcctrl_reg |= ADC_InitStruct->ADC_ExternalTrigConv&ADC_CTRL_ConvTrig_Mask;
	adcctrl_reg |= ADC_CTRL_ADCCAL_Set;
	//ADCSEQ
	adcseq_reg &= ~ADC_SEQ_Set;
	adcseq_reg |= ADC_InitStruct->ADC_ScanMode&ADC_SEQ_Set;
	
	adcseq_reg &= ~ADC_SEQ_Num_Mask;
	adcseq_reg |= (ADC_InitStruct->ADC_ChannelNum<<1)&ADC_SEQ_Num_Mask;
	
	ADCx->ADCCFG = adccfg_reg;
	ADCx->ADCCTRL = adcctrl_reg;
	ADCx->ADCSEQ = adcseq_reg;
	
}

/**
  * @brief  Fills each ADC_InitStruct member with its default value.
  * @param  ADC_InitStruct : pointer to an ADC_InitTypeDef structure which will be initialized.
  * @retval None
  */
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct)
{
	
	ADC_InitStruct->ADC_Channel = ADC_Channel_0;
	ADC_InitStruct->ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStruct->ADC_SampleTime = ADC_SampleTime_128Cycles;
	ADC_InitStruct->ADC_ScanMode = ADC_ScanMode_SingleChannel;
	ADC_InitStruct->ADC_ChannelNum = ADC_NumChannel_1;
	
}

/**
  * @brief  Start single CONV the specified ADC peripheral.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @retval None
  */
void ADC_SingleChannelStart(ADC_TypeDef* ADCx)
{
	uint16_t adccfg_reg = ADCx->ADCCFG;
	
	adccfg_reg |= ADC_CFG_CONV_Start;
	
	ADCx->ADCCFG = adccfg_reg;
	
}

/**
  * @brief  Enables or disables the specified ADC request.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  *   Note: ADC2 hasn't a DMA capability.
  * @param  NewState: new state of the selected ADC transfer.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
	if(NewState != DISABLE)
	{
		ADCx->ADCCTRL |= ADC_CTRL_OnOff_Set;
	}
	else
	{
		ADCx->ADCCTRL &= ~ADC_CTRL_OnOff_Set;
	}
	
}

/**
  * @brief  Enables or disables the specified ADC DMA request.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  *   Note: ADC2 hasn't a DMA capability.
  * @param  NewState: new state of the selected ADC DMA transfer.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
	if(NewState != DISABLE)
	{
		ADCx->ADCCFG |= ADC_CFG_DMA_Set;
	}
	else
	{
		ADCx->ADCCFG &= ~ADC_CFG_DMA_Set;
	}
	
}

/**
  * @brief  Enables or disables the specified ADC interrupts.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.   
  * @param  NewState: new state of the specified ADC interrupts.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void ADC_ITConfig(ADC_TypeDef* ADCx,FunctionalState NewState)
{
	
	if(NewState != DISABLE)
	{
		ADCx->ADCCFG |= ADC_CFG_IT_Set;
	}
	else
	{
		ADCx->ADCCFG &= ~ADC_CFG_IT_Set;
	}
		
}




/**
  * @brief  Gets the selected ADC Software start conversion Status.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @retval The new state of ADC  conversion stauts(SET or RESET).
  */
FlagStatus ADC_GetConvStatus(ADC_TypeDef* ADCx)
{

	FlagStatus bitstatus = RESET;

	if(ADCx->ADCCFG&ADC_CFG_Complete_Set)
	{
		
		bitstatus = SET;
	}
	else
	{
		bitstatus = RESET;
	}		

	
	return  bitstatus;
	
}



/**
  * @brief  Returns the last ADCx conversion result data for regular channel.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @retval The Data conversion value.
  */
uint16_t ADC_GetSingleChannelConversionValue(ADC_TypeDef* ADCx)
{
	
	return ((ADCx->ADCDA&ADC_Data_Mask)>>4);
	
}



/**
  * @brief  Enables or disables the analog watchdog 
  * @param  ADCx: where x can be 0  to select the ADC peripheral.
  * @retval None	  
  */
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
		if(NewState == ENABLE)
			ADCx->ADCCFG |= ADC_CFG_Compare_Set;
		else
			ADCx->ADCCFG &= ~ADC_CFG_Compare_Set;
}



/**
  * @brief  Configures the analog watchdog guarded single channel
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_Value: the ADC channel to configure for the analog watchdog ADC Value. 
  * @retval None
  */
void ADC_AnalogWatchdogConfigMax(ADC_TypeDef* ADCx, uint16_t ADC_Value)
{
	ADCx->ADCDPH = (ADC_Value<<4)&ADC_Data_Mask;
}

/**
  * @brief  Configures the analog watchdog guarded single channel
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @param  ADC_Value: the ADC channel to configure for the analog watchdog ADC Value. 
  * @retval None
  */
void ADC_AnalogWatchdogConfigMin(ADC_TypeDef* ADCx, uint16_t ADC_Value)
{
	ADCx->ADCDPL = (ADC_Value<<4)&ADC_Data_Mask;
}

/**
  * @brief  Checks whether the specified ADC flag is set or not.
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_FLAG: specifies the flag to check. 
  *   This parameter can be one of the following values:
  *     @arg ADC_FLAG_AWD: Analog watchdog flag
  *     @arg ADC_FLAG_EOC: End of conversion flag

  * @retval The new state of ADC_FLAG (SET or RESET).
  */
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint16_t ADC_FLAG)
{
	FlagStatus bitstatus = RESET;
	
	if((ADCx->ADCCFG&ADC_FLAG) != (uint16_t)RESET)
  {
    /* ADC_FLAG is set */
    bitstatus = SET;
  }
  else
  {
    /* ADC_FLAG is reset */
    bitstatus = RESET;
  }
	return  bitstatus;	
	
}

/**
  * @brief  Clears the ADCx's pending flags.
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_FLAG: specifies the flag to clear. 
  *   This parameter can be any combination of the following values:
  *     @arg ADC_FLAG_AWD: Analog watchdog flag
  *     @arg ADC_FLAG_EOC: End of conversion flag
  * @retval None
  */
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint16_t ADC_FLAG)
{
	uint16_t adccfg_reg = ADCx->ADCCFG;
	
	adccfg_reg |= ADC_FLAG;
	
	ADCx->ADCCFG = adccfg_reg;
}

/**
  * @brief  Checks whether the specified ADC interrupt has occurred or not.
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_IT: specifies the ADC interrupt source to check. 
  *   This parameter can be one of the following values:
  *     @arg ADC_IT_EOC: End of conversion interrupt mask
  *     @arg ADC_IT_AWD: Analog watchdog interrupt mask
  * @retval The new state of ADC_IT (SET or RESET).
  */
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT)
{
	ITStatus bitstatus = RESET;
	uint32_t enablestatus = 0;
	  /* Get the ADC_IT enable bit status */
  enablestatus = (ADCx->ADCCFG & (uint16_t)ADC_IT) ;
	
	if((ADCx->ADCCFG&enablestatus) != RESET)
	{
		bitstatus = SET;
	}
	else
	{
		bitstatus = RESET;
	}
	
	return bitstatus;
	
}

/**
  * @brief  Clears the ADCx's interrupt pending bits.
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_IT: specifies the ADC interrupt pending bit to clear.
  *   This parameter can be any combination of the following values:
  *     @arg ADC_IT_EOC: End of conversion interrupt mask
  *     @arg ADC_IT_AWD: Analog watchdog interrupt mask
  * @retval None
  */
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT)
{
	uint16_t adccfg_reg = ADCx->ADCCFG;
	
	adccfg_reg |= ADC_IT;
	
	ADCx->ADCCFG = adccfg_reg;
}



/**
  * @brief  Configures the ADC clock (ADCCLK).
  * @param  ADC_ClockDivider: defines the ADC clock divider. This clock is derived from 
  *   the APB2 clock (PCLK2).
  *   This parameter can be one of the following values:
  *     @arg ADC_CLK_PCLK_DIV_2: ADC clock = PCLK2/2
  *     @arg ADC_CLK_PCLK_DIV_4: ADC clock = PCLK2/4
  *     @arg ADC_CLK_PCLK_DIV_6: ADC clock = PCLK2/6
	*			@arg ....
	*			@arg ....
  *     @arg ADC_CLK_PCLK_DIV_128: ADC clock = PCLK2/128
  * @retval None
  */
void ADC_CLKConfig(ADC_TypeDef* ADCx,uint16_t ADC_ClockDivider)
{
	uint16_t adcctrl_reg = 0;
	
	adcctrl_reg = ADCx->ADCCTRL;
	adcctrl_reg &= ~ADC_CTRL_CLKDIV_Mask;
	adcctrl_reg |= (ADC_ClockDivider<<4)&ADC_CTRL_CLKDIV_Mask;
	
	ADCx->ADCCTRL = adcctrl_reg;
	
	
}


/**
  * @brief  Configures the ADC clock (ADCCLK).
  * @param  ADC_RefVoltage: defines the ADC voltage Ref. This clock is derived from 
  *   
  *   This parameter can be one of the following values:
  *     @arg ADC_REF_VOLTAGE_INN1_5: Internal 1.5V reference voltage
  *     @arg ADC_REF_VOLTAGE_VDD: External power supply VDD is used as reference voltage
  *     @arg ADC_REF_VOLTAGE_EXT: External reference voltage
  *     @arg ADC_REF_VOLTAGE_INN: Internal 1.5V reference voltage
  * @retval None
  */
void ADC_REFConfig(ADC_TypeDef* ADCx,uint16_t ADC_RefVoltage)
{
	uint16_t adccfg_reg = 0;
	
	adccfg_reg = ADCx->ADCCFG;
	adccfg_reg &= ~ADC_CFG_Vref_Mask;
	adccfg_reg |= ADC_RefVoltage&ADC_CFG_Vref_Mask;
	
	ADCx->ADCCFG = adccfg_reg;
	
}

/**
  * @brief  ADC_ScanMode_SingleChannel mode the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28   
  * @retval None
  */
void ADC_ChannelSet(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adccfg_reg = 0;
	
	adccfg_reg = ADCx->ADCCFG;
	adccfg_reg &= ~ADC_CFG_CHx_Mask;
	adccfg_reg |= (Channel<<8)&ADC_CFG_CHx_Mask;
	ADCx->ADCCFG = adccfg_reg;
}

/**
  * @brief  Enables or disables the specified ADC ScanMode MultiChannel.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
  * @param  NewState: new state of the selected ADC ScanMode MultiChannel.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */

void ADC_MultiChannelScanCmd(ADC_TypeDef* ADCx,FunctionalState NewState)
{
	uint16_t adcseq_reg = 0;
	adcseq_reg = ADCx->ADCSEQ;
	
	
	if(NewState != DISABLE)
	{
		adcseq_reg &= ~ADC_SEQ_Set;
		adcseq_reg |= ADC_SEQ_Set;
	}
	else
	{
		adcseq_reg &= ~ADC_SEQ_Set;
	}
	ADCx->ADCSEQ = adcseq_reg;	
}
/**
  * @brief  ADC_ScanMode_MultiChannel 1 , the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28  
  * @retval None
  */
void ADC_MultiChannel1Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adccfg_reg = 0;
	adccfg_reg = ADCx->ADCCFG;

	adccfg_reg &= ~ADC_CFG_CHx_Mask;
	adccfg_reg |= (Channel<<8)&ADC_CFG_CHx_Mask;
	
	ADCx->ADCCFG = adccfg_reg;		
}
/**
  * @brief  ADC_ScanMode_MultiChannel 2 , the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28   
  * @retval None
  */
void ADC_MultiChannel2Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adcseq_reg = 0;
	adcseq_reg = ADCx->ADCSEQ;

	adcseq_reg &= ~ADC_SEQ_CH1SEL_Mask;
	adcseq_reg |= (Channel<<5)&ADC_SEQ_CH1SEL_Mask;
	
	ADCx->ADCSEQ = adcseq_reg;
	
}
/**
  * @brief  ADC_ScanMode_MultiChannel 3 , the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28    
  * @retval None
  */
void ADC_MultiChannel3Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adcseq_reg = 0;
	adcseq_reg = ADCx->ADCSEQ;

	adcseq_reg &= ~ADC_SEQ_CH2SEL_Mask;
	adcseq_reg |= (Channel<<10)&ADC_SEQ_CH2SEL_Mask;
	
	ADCx->ADCSEQ = adcseq_reg;	
}
/**
  * @brief  ADC_ScanMode_MultiChannel 4, the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28  
  * @retval None
  */
void ADC_MultiChannel4Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adcchsel_reg = 0;
	adcchsel_reg = ADCx->ADCCHSEL;

	adcchsel_reg &= ~ADC_CHSEL_CH3SEL_Mask;
	adcchsel_reg |= (Channel<<0)&ADC_CHSEL_CH3SEL_Mask;
	
	ADCx->ADCCHSEL = adcchsel_reg;		
}
/**
  * @brief  ADC_ScanMode_MultiChannel 5, the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28  
  * @retval None
  */
void ADC_MultiChannel5Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adcchsel_reg = 0;
	adcchsel_reg = ADCx->ADCCHSEL;

	adcchsel_reg &= ~ADC_CHSEL_CH4SEL_Mask;
	adcchsel_reg |= (Channel<<5)&ADC_CHSEL_CH4SEL_Mask;
	
	ADCx->ADCCHSEL = adcchsel_reg;			
}
/**
  * @brief  ADC_ScanMode_MultiChannel 6, the specified ADC Channelx config.
  * @param  ADCx: where x can be 0 select the ADC peripheral.
	*	@param Channel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28 
  * @retval None
  */
void ADC_MultiChannel6Config(ADC_TypeDef* ADCx,uint8_t Channel)
{
	uint16_t adcchsel_reg = 0;
	adcchsel_reg = ADCx->ADCCHSEL;

	adcchsel_reg &= ~ADC_CHSEL_CH5SEL_Mask;
	adcchsel_reg |= (Channel<<10)&ADC_CHSEL_CH5SEL_Mask;
	
	ADCx->ADCCHSEL = adcchsel_reg;		
}

/**
  * @brief  ADC_ScanMode_MultiChannel Start the specified ADC peripheral.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
	*	@param FirstChannel This parameter can be one of the following values:
  *  ADC_Channel_0 ~ADC_Channel_28 
  * @retval None
  */
void ADC_MultiChannelStart(ADC_TypeDef* ADCx,uint8_t FirstChannel)
{
	uint16_t adccfg_reg = 0;
	adccfg_reg = ADCx->ADCCFG;

	adccfg_reg &= ~ADC_CFG_CHx_Mask;
	adccfg_reg |= (FirstChannel<<8)&ADC_CFG_CHx_Mask;
	
	ADCx->ADCCFG = adccfg_reg|ADC_CFG_CONV_Start;		
}


/**
  * @brief  Returns the last ADCx MultiChannel 1 conversion result data.
  * @param  ADCx: where x can be 0 to select the ADC peripheral.
  * @retval The Data conversion value.
  */
uint16_t ADC_GetMultiChannelxConversionValue(ADC_TypeDef* ADCx,uint8_t ADC_MultiNumChannel_x)
{
	uint16_t ret_value = 0;
	
	if(ADC_MultiNumChannel_x == ADC_NumChannel_1)
	{
		ret_value = ((ADCx->ADCDALAT0&ADC_DATAT0_Mask)>>4);
	}
	else if(ADC_MultiNumChannel_x == ADC_NumChannel_2)
	{
		ret_value = ((ADCx->ADCDALAT1&ADC_DATAT1_Mask)>>4);
	}	
	else if(ADC_MultiNumChannel_x == ADC_NumChannel_3)
	{
		ret_value = ((ADCx->ADCDALAT2&ADC_DATAT2_Mask)>>4);
	}	
	else if(ADC_MultiNumChannel_x == ADC_NumChannel_4)
	{
		ret_value = ((ADCx->ADCDALAT3&ADC_DATAT3_Mask)>>4);
	}	
	else if(ADC_MultiNumChannel_x == ADC_NumChannel_5)
	{
		ret_value = ((ADCx->ADCDALAT4&ADC_DATAT4_Mask)>>4);
	}	
	else if(ADC_MultiNumChannel_x == ADC_NumChannel_6)
	{
		ret_value = ((ADCx->ADCDA&ADC_Data_Mask)>>4);
	}		
	
	return ret_value;
	
}


void ADC_AMPCmd(ADC_TypeDef* ADCx,FunctionalState NewState)
{
	uint16_t adcctrl_reg = ADCx->ADCCTRL;
	
	if(NewState != DISABLE)
	{
		adcctrl_reg &= ~ADC_CTRL_AMP_Set;
		adcctrl_reg |= ADC_CTRL_AMP_Set;
	}
	else
	{
		adcctrl_reg &= ~ADC_CTRL_AMP_Set;
	}
	ADCx->ADCCTRL = adcctrl_reg;
}
void ADC_AMPGainSet(ADC_TypeDef* ADCx,uint8_t AMPGain)
{
	uint16_t adcctrl_reg = ADCx->ADCCTRL;
	
	adcctrl_reg &= ~ADC_CTRL_AMPGain_Mask;
	adcctrl_reg |= (AMPGain<<11)&ADC_CTRL_AMPGain_Mask;
	
	ADCx->ADCCTRL = adcctrl_reg;
}








